import validator from 'validator';
import jwt from 'jsonwebtoken';
import { Op } from 'sequelize';
import bcrypt from 'bcryptjs';
import { QueryWhereConf, AddUserError } from 'definitions/admin-user';
import { QueryAllConf } from 'definitions/common';
import models from '../../models';
import { sendEmail } from '../../email';
import { JWT_SECRET, USER_INIT_PASSWORD } from '../../config';

const { AdminUser, AdminAccessRouter } = models;

const createToken = async (user, secret, expiresIn) => {
  const { id, role_id, role } = user;
  return await jwt.sign({ id, role_id, sign: role ? role.sign : 'unknow' }, secret, {
    expiresIn
  });
};

export default function (router) {
  /**
   * 后台用户登录接口
   * 需要login和password参数
   */
  router.post('/api/admin/user/login', async ctx => {
    const { login, password } = ctx.request.body;
    // 验证参数
    if (!login || !validator.isLength(login, { min: 2, max: 40 })) {
      await ctx.json(false, 'validate-error', { login: '用户名或邮箱错误' });
      return;
    }
    if (!password || !validator.isLength(password, { min: 6, max: 42 })) {
      await ctx.json(false, 'validate-error', { password: '密码格式错误' });
      return;
    }
    // 查找数据库中是否存在指定邮箱和密码的记录
    const user = await AdminUser.findByLogin(login);
    if (!user) {
      await ctx.json(false, 'validate-error', { login: '邮箱尚未注册' });
      return;
    }
    // 校验密码
    const isPasswordValid = await user.validatePassword(password);
    if (!isPasswordValid) {
      await ctx.json(false, 'validate-error', { password: '密码错误，如需重置密码请联系管理员' });
      return;
    }

    // 验证完毕，生成token
    const token = await createToken(user, JWT_SECRET, '1d');
    ctx.cookies.set('mbook-admin-token', token, { httpOnly: false });
    await ctx.json(true, 'success', token);
  });

  /**
   * 获取用户信息
   */
  router.get('/api/admin/user/current', async ctx => {
    if (!ctx.state.user) return;
    const userid = ctx.state.user.id;
    const user = await AdminUser.findByPk(userid, {
      include: [{ model: models.AdminRole, as: 'role', attributes: ['id', 'name', 'sign'] }]
    });
    if (user && user.id) {
      // 获取用户可以访问的路由
      const accessRouters = await AdminAccessRouter.findOne({ where: { role_id: user.role_id } });
      await ctx.json(true, 'success', {
        username: user.username,
        avatar: user.avatar,
        email: user.email,
        createdAt: user.createdAt,
        updatedAt: user.updatedAt,
        role: user.role,
        creator: user.creator,
        accessRouter: accessRouters ? accessRouters.routers : []
      });
    } else {
      await ctx.json(false, '暂无此用户');
    }
  });

  /**
   * 获取用户列表
   * @param {String} username 用户名查询
   * @param {String} role 角色id
   * @param {String} email 邮箱查询
   * @param {String} sort 排序选项，比如 createdAt_DESC
   * @param {Boolean} all 是否查询全部
   * @param {Number} page 查询页数
   * @param {Number} limit 每页限制数
   */
  router.get('/api/admin/admin-user', async ctx => {
    const { role, username, email, sorter, all } = ctx.request.query;
    const { page, limit } = ctx.parsePageAndLimit(ctx.request.query);

    let whereConf: QueryWhereConf = {};
    if (role) {
      whereConf.role_id = role;
    }
    if (username) {
      whereConf.username = {
        [Op.like]: `%${username}%`
      };
    }
    if (email) {
      whereConf.email = {
        [Op.like]: `%${email}%`
      };
    }
    if (ctx.state.user.sign === 'user') {
      whereConf.id = ctx.state.user.id;
    }

    // 排序规则
    let order = [['created_at', 'DESC']];
    if (sorter) {
      const sortName = sorter.split('_')[0].replace('createdAt', 'created_at').replace('updatedAt', 'updated_at');
      const sortFunc = sorter.split('_')[1].replace('ascend', 'ASC').replace('descend', 'DESC');
      order = [[sortName, sortFunc]];
    }

    // 是否获取全部数据
    const allConf: QueryAllConf = {};
    if (!all) {
      allConf.offset = (page - 1) * limit;
      allConf.limit = limit;
    }

    const users = await AdminUser.findAndCountAll({
      ...allConf,
      where: whereConf,
      order: order,
      attributes: { exclude: ['role_id', 'department_id'] },
      include: [{ model: models.AdminRole, attributes: ['id', 'name'], as: 'role' }]
    });
    await ctx.json(true, '获取用户成功', { total: users.count, list: users.rows });
  });

  /**
   * 新增用户
   * @param {String} username 用户名
   * @param {String} email 邮箱
   * @param {String} avatar 头像
   * @param {String} role 角色
   */
  router.post('/api/admin/admin-user', async ctx => {
    let { username = '', email = '', avatar = '', role } = ctx.request.body;
    role = role.toString();
    // 验证参数
    let error: AddUserError = {};
    if (!username || !validator.isLength(username, { min: 2, max: 10 })) error.username = '用户名格式错误';
    if (await AdminUser.isRepeat('username', username)) error.username = '用户名重复';
    if (!email || !validator.isEmail(email)) error.email = '邮箱格式错误';
    if (await AdminUser.isRepeat('email', email)) error.email = '邮箱重复';
    if (!role || !validator.isInt(role)) error.role = '请选择角色';
    if (JSON.stringify(error) !== '{}') {
      await ctx.json(false, 'validate-error', error);
      return;
    }

    // 验证是否有权限创建
    if (ctx.state.user.sign !== 'manager') {
      ctx.status = 403; // Forbidden
      console.log(`${ctx.method} ${ctx.url} - 403 Forbidden`);
      return;
    }

    // 创建用户
    const randomPassword = Math.random().toString().slice(-8);
    const currentUser = await AdminUser.findByPk(ctx.state.user.id, { attributes: ['username'] });
    const newUser = await AdminUser.create({
      username,
      avatar: avatar || 'https://picture-1256514897.file.myqcloud.com/book/codes/default-avatar.png',
      email,
      role_id: role.toString(),
      password: randomPassword,
      creator: currentUser.username || '系统初始化'
    });
    if (newUser && newUser.id) {
      /**
       * 发送邀请邮件给用户
       * 产生一个临时的key值存放在redis中，临时的key值会下发到前端
       * 前端设置密码的时候判断这个key是否在redis中存在，如果存在设置有有效，不存在则显示过期
       */
      sendEmail(newUser.email, 'userCreatedNotice', {
        creator: currentUser.username,
        newUserName: newUser.username,
        newEmail: newUser.email,
        password: randomPassword,
        link: 'https://admin.lantingshucheng.com/v2/#/login'
      })
        .then(() => {
          console.log(`账号开通 ${newUser.username}(${newUser.email}) 的邮件已经发送`);
        })
        .catch(err => {
          console.log(`账号开通 ${newUser.username}(${newUser.email}) 的邮件发送失败，${err.toString()}`);
        });
      await ctx.json(true, '用户创建成功', newUser);
    } else {
      await ctx.json(false, '用户创建失败');
    }
  });

  /**
   * 修改权限
   * @param {String} name 用户名称
   * @param {String} email 用户邮箱
   * @param {String} avatar 用户头像
   * @param {String} role 用户角色
   * @param {Boolean} reset 是否重置密码
   */
  router.put('/api/admin/admin-user/:id', async ctx => {
    let { username = '', email = '', avatar = '', role, reset = false } = ctx.request.body;
    const userId = ctx.params.id;
    // 验证参数
    let error: AddUserError = {};
    let params: AddUserError = {};

    if (username) {
      if (!validator.isLength(username, { min: 2, max: 20 })) error.username = '用户名格式错误';
      if (await AdminUser.isRepeat('username', username, 'self')) error.username = '用户名重复';
      params.username = username;
    }

    if (email) {
      if (!validator.isEmail(email)) error.email = '邮箱格式错误';
      if (await AdminUser.isRepeat('email', email, 'self')) error.email = '邮箱重复';
      params.email = email;
    }

    if (avatar) {
      params.avatar = avatar;
    }

    if (role) {
      params.role_id = role.toString();
    }

    if (JSON.stringify(error) !== '{}') {
      await ctx.json(false, 'validate-error', error);
      return;
    }

    if (reset) {
      params.password = await bcrypt.hash(USER_INIT_PASSWORD, 12);
    }

    // 更新角色
    const updateResult = await AdminUser.update(params, { where: { id: userId } });
    if (updateResult[0] === 1) {
      await ctx.json(true, '更新用户成功');
    } else {
      await ctx.json(false, '更新用户失败');
    }
  });

  /**
   * 删除用户
   */
  router.delete('/api/admin/admin-user/:id', async ctx => {
    const userId = ctx.params.id;

    // 验证是否有权限删除
    if (ctx.state.user.sign !== 'manager') {
      ctx.status = 403; // Forbidden
      console.log(`${ctx.method} ${ctx.url} - 403 Forbidden`);
      return;
    }

    // 删除用户
    const deleteResult = await AdminUser.destroy({ where: { id: userId } });
    if (deleteResult === 1) {
      await ctx.json(true, '删除用户成功');
    } else {
      await ctx.json(false, '删除用户失败');
    }
  });
}
